package core;

import java.awt.Color;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;

public class Lines extends VectorialObject {
	
	private List<LinePoints> mLines;
	
	private Line2D.Double line;
	
	public Lines() {
		mLines = new ArrayList<Lines.LinePoints>();
		line = new Line2D.Double();
	}
	
	@Override
	public void draw(OurGraphics g2) {
		
		super.draw(g2);
		
		g2.setLinePattern(OurGraphics.NO_DASH);
		
		int dx = g2.getClip().getPoint1().getX();
		int dy = g2.getClip().getPoint1().getY();
		
		for(LinePoints l : mLines) {
			
			line.x1 = l.p1.getX();
			line.y1 = l.p1.getY();
			line.x2 = l.p2.getX();
			line.y2 = l.p2.getY();
			
			g2.setColor(l.color);
			g2.drawLine((int)line.x1 - dx, (int)line.y1 - dy, (int)line.x2 - dx, (int)line.y2 - dy);
			
			drawVertice(l.p1, g2);
			drawVertice(l.p2, g2);
		}
		
		if(isSelected()){
			drawSelectionSquare(g2);
		}
	}
	
	public boolean intersect(Point3D pt) {
		
		for(LinePoints line : mLines){
			if(Geom.lineIntersects(line.p1, line.p2, pt, 5)){
				return true;
			}
		}
		
		return false;
	}
	
	public void join(Point3D pt1, Point3D pt2, Color c) {
		
		if(!mVertices.contains(pt1) || !mVertices.contains(pt2)){
			throw new IllegalArgumentException("Ponto inexistente");
		}
		
		LinePoints line = new LinePoints();
		line.p1 = pt1;
		line.p2 = pt2;
		line.color = c;
		
		mLines.add(line);
	}
	
	public void join(int[] indices, Color c) {
		
		List<Point3D> pts = new ArrayList<Point3D>();
		
		for(int indice : indices) {
			
			if(indice < 0 || indice > mVertices.size()){
				throw new IllegalArgumentException("Ponto inexistente");
			}
			
			pts.add(mVertices.get(indice));
		}
		
		join(pts.toArray(new Point3D[0]), c);
	}
	
	public void join(Point3D[] pts, Color c) {
		for(int i = 0; i < pts.length-1; i++) {
			join(pts[i], pts[i+1], c);
		}
	}
	
	public void clipping(int xMin, int yMin, int xMax, int yMax) {

		PointRegion prCorrente;
		PointRegion prGambis;

		ArrayList<LinePoints> mResultingLines = new ArrayList<LinePoints>();

		for (LinePoints l : mLines) {
			PointRegion pr1 = classificar(xMin, yMin, xMax, yMax, l.p1);
			PointRegion pr2 = classificar(xMin, yMin, xMax, yMax, l.p2);

			while (necessarioClipping(pr1, pr2)) {

				if (pr1.regiao.size() == 0) {
					prCorrente = pr2;
					prGambis = pr1;
				} else {
					prCorrente = pr1;
					prGambis = pr2;
				}

				Point3D novoPonto = new Point3D(0, 0);

				if (prCorrente.regiao.contains("TOPO")) {
					int novoY = yMax;
					int novoX =  Geom.calculaX(prCorrente.pt.getX(),
							prGambis.pt.getX(), prCorrente.pt.getY(),
							prGambis.pt.getY(), novoY);

					novoPonto.setX(novoX);
					novoPonto.setY(novoY);

					prCorrente.pt = novoPonto;

				} else if (prCorrente.regiao.contains("BASE")) {
					int novoY = yMin;
					int novoX =  Geom.calculaX(prCorrente.pt.getX(),
							prGambis.pt.getX(), prCorrente.pt.getY(),
							prGambis.pt.getY(), novoY);

					novoPonto.setX(novoX);
					novoPonto.setY(novoY);

					prCorrente.pt = novoPonto;

				} else if (prCorrente.regiao.contains("ESQ")) {
					int novoX = xMin;
					int novoY = Geom.calculaY(prCorrente.pt.getX(),
							prGambis.pt.getX(), prCorrente.pt.getY(),
							prGambis.pt.getY(), novoX);

					novoPonto.setX(novoX);
					novoPonto.setY(novoY);

					prCorrente.pt = novoPonto;

				} else if (prCorrente.regiao.contains("DIR")) {
					int novoX = xMax;
					int novoY =  Geom.calculaY(prCorrente.pt.getX(),
							prGambis.pt.getX(), prCorrente.pt.getY(),
							prGambis.pt.getY(), novoX);

					novoPonto.setX(novoX);
					novoPonto.setY(novoY);

					prCorrente.pt = novoPonto;
				}

				mVertices.remove(novoPonto);

				l.p1 = novoPonto;
				l.p2 = prGambis.pt;

				pr1 = classificar(xMin, yMin, xMax, yMax, l.p1);
				pr2 = classificar(xMin, yMin, xMax, yMax, l.p2);
			}

			if (pr1.regiao.size() == 0 && pr2.regiao.size() == 0) {
				mResultingLines.add(l);
				continue;
			}

		}

		mLines.clear();
		mVertices.clear();
		mLines.addAll(mResultingLines);

		for (LinePoints l : mLines) {
			mVertices.add(l.p1);
			mVertices.add(l.p2);
		}
	}
	
    public boolean necessarioClipping(PointRegion pr1, PointRegion pr2) {
    	
    	if(pr1.regiao.size() == 0 && pr2.regiao.size() == 0) {
    		return false;
    	}
    	
    	for(String regiao : pr1.regiao) {
    		if(pr2.regiao.contains(regiao)) {
    			return false;
    		}
    	}
    	
    	return true;
    }
    
    private PointRegion classificar(int xMin, int yMin, int xMax, int yMax, Point3D p) {
    	PointRegion pr = new PointRegion();
    	
    	if(p.getX() < xMin) {
    		pr.regiao.add("ESQ");
    	} else if(p.getX() > xMax) {
    		pr.regiao.add("DIR");
    	}
    	
    	if(p.getY() < yMin) {
    		pr.regiao.add("BASE");
    	} else if(p.getY() > yMax) {
    		pr.regiao.add("TOPO");
    	}
    	
    	pr.pt = p;
    	
    	return pr;
    }
    
    private class PointRegion {
    	public Point3D pt;
    	public List<String> regiao = new ArrayList<String>();
    }
	
	private static class LinePoints {
		Point3D p1;
		Point3D p2;
		Color color;
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		
	}
}
